﻿#region NeoPatterns
// 
// NeoPatterns framework is released under LGPLv3 license.
// See http://www.opensource.org/licenses/lgpl-3.0.html for more details.
// 
// Please visit http://neopatterns.wikidot.com for more information about NeoPatterns
// 
// Copyright (c) Pascal Craponne 2008
// 
#endregion

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using NeoPatterns.Core.Aop;
using NeoPatterns.Utility;

namespace NeoPatterns.Core.Aop
{
    /// <summary>
    /// Represents a pointcut expressed with literal text.
    /// Syntax for pointcut is:
    /// ["&lt;objectNameWildcard>"|'&lt;objectNameWildcard>'] [&lt;typeFullNameWildcard>] [&lt;methodNameWildcard>]
    /// </summary>
    public class LiteralPointcut : IPointcut
    {
        private NameMatcher objectNameMatcher;
        private NameMatcher typeFullNameMatcher;
        private NameMatcher methodNameMatcher;

        /// <summary>
        /// Literal pointcut expression
        /// </summary>
        public string Expression
        {
            get
            {
                var expressions = new List<string>();
                if (objectNameMatcher != null)
                    expressions.Add(string.Format(CultureInfo.InvariantCulture, "'{0}'", objectNameMatcher.Expression));
                if (typeFullNameMatcher != null)
                    expressions.Add(typeFullNameMatcher.Expression);
                if (methodNameMatcher != null)
                    expressions.Add(methodNameMatcher.Expression);
                return string.Join(" ", expressions.ToArray());
            }
            set
            {
                var expressions = value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                objectNameMatcher = null;
                typeFullNameMatcher = null;
                methodNameMatcher = null;
                if (expressions[0][0] == '"' || expressions[0][0] == '\'')
                {
                    objectNameMatcher = new NameMatcher(expressions[0].Substring(1, expressions[0].Length - 1));
                    expressions.RemoveAt(0);
                }
                if (expressions.Count > 0)
                {
                    typeFullNameMatcher = new NameMatcher(expressions[0]);
                    if (expressions.Count > 1)
                        methodNameMatcher = new NameMatcher(expressions[1]);
                }
            }
        }

        public string NameMatch
        {
            get
            {
                return objectNameMatcher != null ? objectNameMatcher.Expression : null;
            }
            set
            {
                if (value != null)
                    objectNameMatcher = new NameMatcher(value);
                else
                    objectNameMatcher = null;
            }
        }

        public string TypeMatch
        {
            get
            {
                return typeFullNameMatcher != null ? typeFullNameMatcher.Expression : null;
            }
            set
            {
                if (value != null)
                    typeFullNameMatcher = new NameMatcher(value);
                else
                    typeFullNameMatcher = null;
            }
        }

        public string MethodMatch
        {
            get
            {
                return methodNameMatcher != null ? methodNameMatcher.Expression : null;
            }
            set
            {
                if (value != null)
                    methodNameMatcher = new NameMatcher(value);
                else
                    methodNameMatcher = null;
            }
        }

        public bool Select(Type type, string objectName)
        {
            // first test on object name (probably the most easy to implement)
            if (methodNameMatcher != null && !methodNameMatcher.Matches(objectName))
                return false;
            // second test on type full name (including namespace)
            // probably not a good thing to do
            if (typeFullNameMatcher != null && !methodNameMatcher.Matches(type.FullName))
                return false;
            return true;
        }

        public bool Select(MemberInfo memberInfo)
        {
            if (methodNameMatcher != null && !methodNameMatcher.Matches(memberInfo.Name))
                return false;
            return true;
        }
    }
}